package jmine.tec.rpc.server.representation.representers.lazy;

import jmine.tec.rpc.common.entity.EntityRepresentation;
import jmine.tec.rpc.common.entity.EntityRest;
import jmine.tec.rpc.common.provider.RestServiceProvider;
import jmine.tec.rpc.server.representation.FallbackRepresenterFactory;
import jmine.tec.rpc.server.representation.Representer;

/**
 * FallbackRepresenterFactory que retorna, quando possível representers lazy.
 * 
 * @author lundberg
 */
public class LazyFallbackRepresenterFactory implements FallbackRepresenterFactory {

    private FallbackRepresenterFactory fallback;

    private RestServiceProvider provider;

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    public <R, E> Representer<R, E> create(Class<R> representationClass, Class<E> representedClass) {
        if (this.isLazyable(representationClass, representedClass)) {
            return new LazyRepresenter(representationClass, this.serviceFor((Class<? extends EntityRepresentation>) representationClass));
        } else {
            return this.fallback.create(representationClass, representedClass);
        }
    }

    /**
     * Verifica se é possível representar esta classe de forma lazy
     * 
     * @param <R> tipo da representação
     * @param <E> tipo do objeto representado
     * @param representationClass representationClass
     * @param representedClass representedClass
     * @return boolean
     */
    protected <R, E> boolean isLazyable(Class<R> representationClass, Class<E> representedClass) {
        return LazyPersistableBean.class.isAssignableFrom(representedClass)
                && EntityRepresentation.class.isAssignableFrom(representationClass);
    }

    /**
     * Obtém o EntityRestService adequado à representação
     * 
     * @param <R> tipo da representação
     * @param representationClass representationClass
     * @return EntityRestService
     */
    private <R extends EntityRepresentation> EntityRest<R> serviceFor(Class<R> representationClass) {
        return this.provider.provideByRepresentation(representationClass);
    }

    /**
     * @param fallback the fallback to set
     */
    public void setFallback(FallbackRepresenterFactory fallback) {
        this.fallback = fallback;
    }

    /**
     * @param provider the provider to set
     */
    public void setProvider(RestServiceProvider provider) {
        this.provider = provider;
    }
}
